package com.slipper.ai.flow;

import com.google.gson.reflect.TypeToken;
import com.slipper.ai.flow.vo.*;
import com.slipper.core.gson.GsonUtil;
import com.slipper.util.Tool;

import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class Parser {
    public static FlowVO parse(String json) {
        FlowVO vo = new FlowVO();

        Map<String, Object> map = GsonUtil.toMap(json);
        if (map == null) return null;

        Object nodes = map.get("nodes");
        Object edges = map.get("edges");

        if (nodes instanceof List<?> nodeList) {
            nodeList.forEach(node -> {
                if (node instanceof Map<?, ?> nodeMap) {
                    if (nodeMap.get("data") instanceof Map<?, ?> dataMap) {
                        vo.addNode(parseNode((String) dataMap.get("type"), GsonUtil.toJson(dataMap), nodeMap));
                    }
                }
            });
        }

        Type type = new TypeToken<List<LineVO>>(){}.getType();
        vo.setLines(GsonUtil.fromJson(GsonUtil.toJson(edges), type));
        return vo;
    }

    public static NodeVO parseNode(String type, String dataJson, Map<?, ?> nodeMap) {
        NodeVO vo = switch (type) {
            case NodeVO.TYPE_START -> GsonUtil.fromJson(dataJson, StartNodeVO.class);
            case NodeVO.TYPE_LLM -> GsonUtil.fromJson(dataJson, LlmNodeVO.class);
            case NodeVO.TYPE_CLASSIFIER -> GsonUtil.fromJson(dataJson, ClassifierNodeVO.class);
            case NodeVO.TYPE_KNOWLEDGE -> GsonUtil.fromJson(dataJson, KnowledgeNodeVO.class);
            case NodeVO.TYPE_CONDITION -> GsonUtil.fromJson(dataJson, ConditionNodeVO.class);
            case NodeVO.TYPE_SCRIPT -> GsonUtil.fromJson(dataJson, ScriptNodeVO.class);
            case NodeVO.TYPE_HTTP -> GsonUtil.fromJson(dataJson, HttpNodeVO.class);
            case NodeVO.TYPE_REPLY -> GsonUtil.fromJson(dataJson, ReplyNodeVO.class);
            case NodeVO.TYPE_END -> GsonUtil.fromJson(dataJson, EndNodeVO.class);
            default -> null;
        };

        if (vo != null) {
            vo.setId((String) nodeMap.get("id"));
            vo.setName((String) nodeMap.get("label"));
        }

        return vo;
    }

    public static String parseSymbol(String tpl, Map<?, ?> dataMap) {
        if (Tool.isBlank(tpl) || dataMap == null || dataMap.isEmpty()) return tpl;

        String result = tpl;
        for (Map.Entry<?, ?> entry : dataMap.entrySet()) {
            String regex = "\\{\\{" + entry.getKey() + "}}";
            result = result.replaceAll(regex, entry.getValue() == null ? "" : String.valueOf(entry.getValue()));
        }

        return result;
    }

    public static String parseVariable(String paramId, ResultVO result) {
        if (Tool.isBlank(paramId)) return "";
        String[] keys = paramId.split("\\.", 2);
        if (keys.length != 2) return "";

        NodeInstVO instVO = result.getNodeMap().get(keys[0]);
        if (instVO == null || instVO.getOutput() == null) return "";
        Object value = instVO.getOutput().get(keys[1]);
        return value == null ? "" : String.valueOf(value);
    }
}
